import { EventDispatcher } from "../../base/event/EventDispatcher";

enum Event {
    ADD = "LIST.EVENT.ADD",
    REMOVE = "LIST.EVENT.REMOVE",
    UPDATE = "LIST.EVENT.UPDATE",
    CLEAR = "LIST.EVENT.CLEAR",
}

/**
 * 列表
 */
export class List<T> extends EventDispatcher {
    
    static Event = Event;

    private _arr: T[];
    
    /**
     * 是否保证元素的唯一性
     */
    private _only: boolean;

    /**
     * 长度，建议通过length属性获取
     * @deprecated
     */
    public get count():number{
        return this._arr.length;
    }

    /**
     * 长度
     * 
     */
    public get length():number{
        return this._arr.length;
    }
    
    /**
     * 
     * @param only 确保数据的唯一性
     */
    constructor(only:boolean=false) {
        super();
        this._only = only;
        this._arr = [];
    }

    /**
     * 添加到末尾(注意如果保证唯一性，那么重复时就直接返回)
     * @param value 
     */
    push(value: T): boolean {
        if (this._only) {
            let index: number = this._arr.indexOf(value);
            if (index >= 0) {
                return false;
            }
        }
        this._arr.push(value);
        if (this.hasListener(List.Event.ADD)) {
            this.event(List.Event.ADD, value);
        }
        return true;
    }

    /**
     * 添加到列表头部(注意如果保证唯一性，那么重复时就直接返回)
     * @param value 
     * @returns 
     */
    unshift(value: T): boolean {
        if (this._only) {
            let index: number = this._arr.indexOf(value);
            if (index >= 0) {
                return false;
            }
        }
        this._arr.unshift(value);
        if (this.hasListener(List.Event.ADD)) {
            this.event(List.Event.ADD, value);
        }
        return true;
    }

    /**
     * 获取并删除最后一个元素
     * @returns 
     */
    pop(): T | null | undefined {
        if (this._arr.length > 0) {
            const result = this._arr.pop();
            if (this.hasListener(List.Event.REMOVE)) {
                this.event(List.Event.REMOVE, result);
            }
            return result;
        }
        return null;
    }

    /**
     * 获取并删除第一个元素
     * @returns 
     */
    shift(): T | null | undefined {
        if (this._arr.length > 0) {
            const result = this._arr.shift();
            if (this.hasListener(List.Event.REMOVE)) {
                this.event(List.Event.REMOVE, result);
            }
            return result;
        }
        return null;
    }

    /**
     * 删除指定索引的元素
     * @param index 
     */
    removeAt(index: number): T|null {
        if (index >= this._arr.length) {
            console.warn("删除索引超出范围！");
            return null;
        }
        const result = this._arr[index];
        this._arr.splice(index, 1);
        if (this.hasListener(List.Event.REMOVE)) {
            this.event(List.Event.REMOVE, result);
        }
        return result;
    }

    /**
     * 删除元素
     * @param value 
     */
    remove(value: T): void {
        let index: number = this._arr.indexOf(value);
        if (index < 0) {
            throw new Error("要删除的内容不在列表中！" + value);
        }
        const result = this._arr[index];
        this._arr.splice(index, 1);
        if (this.hasListener(List.Event.REMOVE)) {
            this.event(List.Event.REMOVE, result);
        }
    }

    /**
     * 移除所有元素
     */
    clear(): void {
        this._arr.length = 0;
        if (this.hasListener(List.Event.CLEAR)) {
            this.event(List.Event.CLEAR);
        }
    }

    /**
     * 查找元素
     * @param value 
     * @returns 
     */
    find(predicate: (value: T, index: number, obj: T[]) => unknown): T|undefined {
        return this._arr.find(predicate);
    }

    /**
     * 查找元素下标
     * @param value 
     * @returns 
     */
    indexOf(value: T, fromIndex?:number): number {
        return this._arr.indexOf(value, fromIndex);
    }

    /**
     * 查找元素下标
     * @param predicate 
     * @returns 
     */
    findIndex(predicate: (value: T, index: number, obj: T[]) => unknown): number {
        let index = this._arr.findIndex(predicate);
        return index;
    }

    /**
     * 获取指定元素
     * @param index 
     * @returns 
     */
    get(index:number):T|null{
        if (index >= this._arr.length) {
            console.warn("删除索引超出范围！");
            return null;
        }
        return this._arr[index];
    }
}